package jlt.SunTime;
import java.util.*;

public class SunTime {
	
	private ZenithValue _zenith = ZenithValue.Official;
	private double _longitude;
	private double _latitude;
	private double _utcOffset;
	private SimpleTimeZone _tz;
	private Calendar _date;
	private int _sunriseTime;
	private int _sunsetTime;
	
	public enum ZenithValue 
	{
		Official (90500),
		Civil (96000),
		Nautical (102000),
		Astronomical (108000);
		
		private long _val;
		
		private ZenithValue(long val)
		{
			_val = val;
		}
		
		public long getCode()
		{
			return _val;
		}
	}
	
	private enum Direction
	{
		Sunrise,Sunset;
	}
	

	public SunTime(double latitude, double longitude, double utcoffset,SimpleTimeZone tz, Calendar dt)
	{

		this._latitude = latitude;
		this._longitude = longitude;
		this._utcOffset = utcoffset;
		this._tz = tz;
		this._date = dt;
		Update();
	}
	
	private void Update()
	{
		_sunriseTime = Calculate(Direction.Sunrise);
		_sunsetTime = Calculate(Direction.Sunset);
	}
	
	private static double Deg2Rad(double angle)
	{
		return Math.PI * angle / 180.0;
	}
	
	private static double Rad2Deg(double angle)
	{
		return 180.0 * angle / Math.PI;
	}
	
	private static double FixValue(double value, double min, double max)
	{
		while (value < min)
			value += (max - min);
		while (value >= max)
			value -= (max - min);
		return value;
	}
	
	public void setLongitude(double val)
	{
		_longitude = val;
		Update();
	}

	public void setLatitude(double val)
	{
		_latitude = val;
		Update();
	}
		
	public void setUtcOffSet(double val)
	{
		_utcOffset = val;
		Update();
	}
	
	public int getRiseTimeSec()
	{ return _sunriseTime;}
	
	public int getSetTimeSec()
	{return _sunsetTime;}
	
	public void SetZenithValue(ZenithValue zenith)
	{
		_zenith = zenith;
		Update();
	}
	
	private int Calculate( Direction direction)
	{
		int N = _date.get(Calendar.DAY_OF_YEAR);
		
		double lngHour = _longitude / 15.0;
		
		double t;
		
		if (direction == Direction.Sunrise)
			t = N + ((6.0 - lngHour) / 24.0);
		else
			t = N + ((18.0 - lngHour) / 24.0);
		
		/* Mean anomoly (M) */
		double M = (0.9856 * t) - 3.289;
		
		/* true longitude (L) */
		double L = M + (1.916 * Math.sin(Deg2Rad(M))) + (0.020 * Math.sin(Deg2Rad(2*M))) + 282.634;
		L = FixValue(L,0,360);
		
		/* right asc (RA) */
		double RA = Rad2Deg(Math.atan(0.91764 * Math.tan(Deg2Rad(L))));
		RA = FixValue(RA,0,360);
		
		/* adjust quadrant of RA */
		double Lquadrant = (Math.floor(L/90.0)) * 90.0;
		double RAquadrant = (Math.floor(RA/90.0)) * 90.0;
		RA = RA + (Lquadrant - RAquadrant);
		
		RA = RA / 15.0;
		
		/* sin cos DEC (sinDec / cosDec) */
		double sinDec = 0.39782 * Math.sin(Deg2Rad(L));
		double cosDec = Math.cos(Math.asin(sinDec));
		
		/* local hour angle (cosH) */
		double cosH = (Math.cos(Deg2Rad(_zenith._val/1000.0f)) - (sinDec * Math.sin(Deg2Rad(_latitude)))) / (cosDec * Math.cos(Deg2Rad(_latitude)));
		
		/* local hour (H) */
		double H;
		
		if (direction == Direction.Sunrise)
			H = 360.0 - Rad2Deg(Math.acos(cosH));
		else
			H = Rad2Deg(Math.acos(cosH));
		
		H = H / 15.0;
		
		/* time (T) */
		double T = H + RA - (0.06571 * t) - 6.622;
		
		/* universal time (T) */
		double UT = T - lngHour;
		
		TimeZone tz = TimeZone.getDefault();
		int utcOffset = tz.getOffset(System.currentTimeMillis())/3600000;
		
		System.out.println("utc offset = " + utcOffset);
		
		UT += utcOffset;

		UT = FixValue(UT,0,24);
		
		return (int)Math.round(UT*3600);
	}

}

